﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;
using System.Xml.Linq;
using System.ComponentModel;
using System.Windows.Data;

namespace WebPythonHost
{
  public static class ApplicationHlp
  {
    public static string MapPath(string path)
    {
      var appDir = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location);
      return Path.Combine(appDir, path);
    }
  }

  static class XElementHlp
  {
    public static string Attribute_Get(this XElement element, XName name)
    {
      if (element != null)
      {
        var attribute = element.Attribute(name);
        if (attribute != null)
          return attribute.Value;
      }
      return null;
    }
    public static string Value_Get(this XElement element)
    {
      return element != null ? element.Value : null;
    }
  }

  static class DictionaryHlp
  {
    public static TValue FindObject<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key) where TValue : class
    {
      TValue value;
      if (dict.TryGetValue(key, out value))
        return value;
      return null;
    }
    public static TValue? FindValue<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key) where TValue : struct
    {
      TValue value;
      if (dict.TryGetValue(key, out value))
        return value;
      return null;
    }
  }

  static class Array<T>
  {
    public static readonly T[] Empty = new T[] { };
  }

  static class CollectionHlp
  {
    public static IList<T> OrEmpty<T>(this IList<T> list)
    {
      return list ?? Array<T>.Empty;
    }
    public static System.Collections.IList OrEmptyIList(this System.Collections.IList list)
    {
      return list ?? Array<object>.Empty;
    }
  }

  static class ObjectHlp
  {
    public static T As<T>(this object obj) where T : class
    {
      return obj as T;
    }
    public static T? AsNullable<T>(this object obj) where T : struct
    {
      return obj as T?;
    }

    //public static void _n<TItem>(this TItem item, Action<TItem> action)
    //{
    //  if (item != null)
    //    action(item);
    //}
    //public static TValue _n<TItem, TValue>(this TItem item, Func<TItem, TValue> getter)
    //{
    //  if (item != null)
    //    return getter(item);
    //  return default(TValue);
    //}
    //public static void _n<TItem>(this TItem? item, Action<TItem> action) where TItem : struct
    //{
    //  if (item != null)
    //    action(item.Value);
    //}
    //public static TValue _n<TItem, TValue>(this TItem? item, Func<TItem, TValue> getter) where TItem : struct
    //{
    //  if (item != null)
    //    return getter(item.Value);
    //  return default(TValue);
    //}
    //public static TValue? _nv<TItem, TValue>(this TItem item, Func<TItem, TValue> getter) where TValue : struct
    //{
    //  if (item != null)
    //    return getter(item);
    //  return null;
    //}
    //public static TValue? _nv<TItem, TValue>(this TItem? item, Func<TItem, TValue> getter)
    //  where TItem : struct
    //  where TValue : struct
    //{
    //  if (item != null)
    //    return getter(item.Value);
    //  return null;
    //}

    public static void _n<TItem>(this TItem item, Action<TItem> action) where TItem : class
    {
      if (item != null)
        action(item);
    }
    public static void _n<TItem>(this TItem? item, Action<TItem> action) where TItem : struct
    {
      if (item != null)
        action(item.Value);
    }

    public static TValue _n<TItem, TValue>(this TItem item, Func<TItem, TValue> getter)
    {
      if (item != null)
        return getter(item);
      return default(TValue);
    }
    public static TValue _n<TItem, TValue>(this TItem? item, Func<TItem, TValue> getter)
      where TItem : struct
    {
      if (item != null)
        return getter(item.Value);
      return default(TValue);
    }
    public static TValue? _nv<TItem, TValue>(this TItem item, Func<TItem, TValue> getter)
      where TValue : struct
    {
      if (item != null)
        return getter(item);
      return null;
    }
    public static TValue? _nv<TItem, TValue>(this TItem? item, Func<TItem, TValue> getter)
      where TItem : struct
      where TValue : struct
    {
      if (item != null)
        return getter(item.Value);
      return null;
    }
  }

  public class DelegatePropertyDescriptor : System.ComponentModel.PropertyDescriptor
  {
    public DelegatePropertyDescriptor(string name, Func<object, object> valueGetter)
      : this(name, valueGetter, null)
    {
    }
    public DelegatePropertyDescriptor(string name, Func<object, object> valueGetter,
      Action<object, object> valueSetter)
      : base(name, Array<Attribute>.Empty)
    {
      this.ValueGetter = valueGetter;
      this.ValueSetter = valueSetter;
    }

    public Func<object, object> ValueGetter { get; set; }
    public Action<object, object> ValueSetter { get; set; }

    public override bool CanResetValue(object component)
    {
      return false;
    }

    public override Type ComponentType
    {
      get { return _ComponentType; }
    }
    public Type ComponentType_Setter
    {
      set { _ComponentType = value ?? typeof(object); }
    }
    Type _ComponentType = typeof(object);

    public override object GetValue(object component)
    {
      return this.ValueGetter != null ? this.ValueGetter(component) : null;
    }

    public override bool IsReadOnly
    {
      get { return this.ValueSetter == null; }
    }

    public override Type PropertyType
    {
      get { return _PropertyType; }
    }
    public Type PropertyType_Setter
    {
      set { _PropertyType = value ?? typeof(object); }
    }
    Type _PropertyType = typeof(object);

    public override void ResetValue(object component)
    {
    }

    public override void SetValue(object component, object value)
    {
      if (this.ValueSetter != null)
      {
        this.ValueSetter(component, value);
      }
    }

    public override bool ShouldSerializeValue(object component)
    {
      return false;
    }

    public override void AddValueChanged(object component, EventHandler handler)
    {
      var notifySource = component as INotifyPropertyChanged;
      if (notifySource != null)
        notifySource.PropertyChanged += (sender, e) => handler(sender, e);
    }
    public override void RemoveValueChanged(object component, EventHandler handler)
    {
      var notifySource = component as INotifyPropertyChanged;
      if (notifySource != null)
        notifySource.PropertyChanged -= (sender, e) => handler(sender, e);
    }
  }

  public class DelegateConverter : IValueConverter
  {
    public DelegateConverter(Func<object, object> converter)
      : this(converter, null)
    {
    }
    public DelegateConverter(Func<object, object> converter, Func<object, object> backConverter)
    {
      this.converter = converter;
      this.backConverter = backConverter;
    }
    readonly Func<object, object> converter;
    readonly Func<object, object> backConverter;

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      var result = converter != null ? converter(value) : null;
      return result;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      var result = backConverter != null ? backConverter(value) : null;
      return result;
    }
  }
}
